package com.gitee.deament.server.core.cli.db.set;

import com.gitee.deament.server.config.SystemConfig;
import com.gitee.deament.server.core.annotation.CliHander;
import com.gitee.deament.server.core.cli.AbstractCli;
import com.gitee.deament.server.core.data.ConnectData;
import com.gitee.deament.server.core.data.DBData;
import com.gitee.deament.server.core.data.datatype.Value;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.util.*;

/**
 * SINTERSTORE destination key [key …]
 * 可用版本： >= 1.0.0
 * 时间复杂度: O(N * M)， N 为给定集合当中基数最小的集合， M 为给定集合的个数。
 * 这个命令类似于 SINTER key [key …] 命令，但它将结果保存到 destination 集合，而不是简单地返回结果集。
 * <p>
 * 如果 destination 集合已经存在，则将其覆盖。
 * <p>
 * destination 可以是 key 本身。
 * <p>
 * 返回值
 * 结果集中的成员数量。
 *
 * @author deament
 */
@CliHander(command = "SINTERSTORE")
public class SINTERSTOREcli extends AbstractCli {
    @Override
    public void executeCli(ChannelHandlerContext channelHandlerContext, String command) {
        List<String> cliValues = getValues(command);
        if (cliValues.size() < 3) {
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("ERR wrong number of arguments for 'SINTERSTORE' command"));
            return;
        }
        int db = ConnectData.SELECT_DB_STORAGE.getUseDB(channelHandlerContext.channel().id().asLongText());
        DBData dbData = SystemConfig.dbData;
        String destination = cliValues.get(1);
        String key = cliValues.get(2);
        List<String> retainKeys = new ArrayList<>();
        try {
            Value<Set<String>> set = SystemConfig.dbData.getSet(db, key);
            Set<String> destinationSet= (Set<String>) SystemConfig.dbData.getSet(db, destination);

            for (int i = 3; i < cliValues.size(); i++) {
                retainKeys.add(cliValues.get(i));
                //监测是否是set类型 如果不是则会抛出异常
                SystemConfig.dbData.getSet(db, cliValues.get(i));
            }

            if(destinationSet!=null ){
                destinationSet.clear();
            }
            if(set==null ||set.getValue().size()==0){
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("0"));
                return;
            }
            HashSet<String> cal = (HashSet<String>)((HashSet<String>) set.getValue()).clone();
            for (String retainKey : retainKeys) {
                Value<Set<String>> other = SystemConfig.dbData.getSet(db, retainKey);
                if(other==null ||other.getValue().size()==0){
                    channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("0"));
                    return;
                }
                cal.retainAll( set.getValue());
            }
            Iterator<String> iterator = cal.iterator();
            while (iterator.hasNext()){
                SystemConfig.dbData.setSetData(db, destination,iterator.next() );
            }
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(cal.size()+""));
            return;


        } catch (Exception e) {
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(e.getMessage()));
            return;
        }

    }
}
